#!/usr/bin/python

import socket

UDP_IP = ""
UDP_PORT = 5748
UDP_PORT_CLIENT = 5749
LOCAL_IP = "localhost"  # TO MODIFY

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # UDP
sock.bind((UDP_IP, UDP_PORT))

connectionServeur = "Serveur TP2"


# Les variable de Key sont les "Headers" du protocole
class Key:
    SOURCE = 'S'
    DESTINATION = 'D'
    PORT = 'P'
    TYPE = 'T'
    CONTENT = 'C'


# Les variables de Type représentent le type de message envoyé
class Type:
    AUTHORIZE = 'A'
    DEAUTHORIZE = 'D'
    TEXT = 'T'
    RESULT = 'R'
    COMMAND = 'C'
    # FILE = 'F'


class Result:
    OK = 'O'
    DENIED = 'X'
    ERROR = 'E'
    WARNING = 'W'


# La classe User appele un constructeur qui stock le nom de l'utilisateur et son IP
class User:
    def __init__(self, name, ip):
        self.name = name
        self.ip = ip

    def __eq__(self, other):
        return self.name == other.name


class Message:
    # Transforme un dictionnaire en String (pour l'analyze du protocole)
    def toString(msg_dict):
        s = ''
        for (k, v) in msg_dict.items():
            s += k + ":" + str(v) + ";"
        return s[:-1]

    # Transforme un string en dictionnaire (pour le protocole)
    def toDictionnary(msg_str):
        key_values = msg_str.split(';')
        msg = {}
        for key_value in key_values:
            pair = key_value.split(':')
            # 0 est la clé , 1 la valeur
            msg[pair[0]] = pair[1]
        return msg

    # Crée un dictionnaire à partir des différentes variables du message.
    def create(source, destination, port, type, content):
        return {Key.SOURCE: source,
                Key.DESTINATION: destination,
                Key.PORT: port,
                Key.TYPE: type,
                Key.CONTENT: content}


def createMessage(source, destination, type, content):
    msg = Message.create(source, destination, UDP_PORT, type, content)
    return bytes(Message.toString(msg), 'UTF-8')

# userList est une liste de l'objet User
userList = {}


# whoIsConnected compare la liste de Users avec ceux présent dans la chatroom
def generateTask(msg, addr):
    if msg[Key.TYPE] == Type.AUTHORIZE:
        print("Authentification", addr)
        IP = addr[0]
        Name = msg[Key.CONTENT]
        if Name in userList.keys():
            print("\tUser déjà existant!", (Name, IP), "DENIED")
            sock.sendto(createMessage("SERVER", addr[0], Type.RESULT, Result.DENIED), addr)
            return
        userList[Name] = User(Name, IP)
        print("\tUser authentifié", (Name, IP))
        sock.sendto(createMessage("SERVER", addr[0], Type.RESULT, Result.OK), addr)
    elif msg[Key.TYPE] == Type.DEAUTHORIZE:
        print("Dé-Authentification", addr)
        IP = addr[0]
        Name = msg[Key.CONTENT]
        if msg[Key.CONTENT] not in userList.keys():
            print("\tUser non existant!", (Name, IP), "DENIED")
            sock.sendto(createMessage("SERVER", addr[0], Type.RESULT, Result.DENIED), addr)
            return
        userList.pop(msg[Key.CONTENT])
        sock.sendto(createMessage("SERVER", addr[0], Type.RESULT, Result.OK), addr)
        print("\tUser dé-authentifié", (Name, IP))
    elif msg[Key.TYPE] == Type.TEXT:
        print("Redirection de message", addr)
        IP = addr[0]
        Name = msg[Key.DESTINATION]
        if Name not in userList.keys():
            print("\tUser non existant!", (Name, IP), "DENIED")
            sock.sendto(createMessage("SERVER", addr[0], Type.RESULT, Result.DENIED), addr)
            return
        sock.sendto(createMessage(msg[Key.SOURCE], msg[Key.DESTINATION], Type.TEXT, msg[Key.CONTENT]), (userList[msg[Key.DESTINATION]].ip, UDP_PORT_CLIENT))
        print("\tMessage réenvoyé", (msg[Key.SOURCE], msg[Key.DESTINATION]), msg[Key.CONTENT])
        sock.sendto(createMessage("SERVER", addr[0], Type.RESULT, Result.OK), addr)
    elif msg[Key.TYPE] == Type.RESULT:
        # TODO : Envoyer le résultat au message/Commande précédent.
        pass
    elif msg[Key.TYPE] == Type.COMMAND:
        # TODO : Executer la commande ex: /whisper /me /pm(nouveau chatroom privée)
        pass


print("Server started")

while True:
    data, addr = sock.recvfrom(1024)  # buffer size is 1024 bytes
    ip, port = addr
    # print("Received message from:", addr)
    generateTask(Message.toDictionnary(str(data, "UTF-8")), addr)
    # sock.sendto(createMessage("SERVER", addr[0], Type.RESULT, Result.OK), addr)
